/*
 * BooleanCalculator.cpp
 *
 *  Created on: 2012. 10. 15.
 *      Author: dalxx
 */

#include <Arduino.h>
#include "BooleanCalculator.h"

#include "ParseTool.h"
#include "Relay.h"

namespace PLCLib {

Relay* BooleanCalculator::FindRelay(char* name, Relay** relay_list, int num_list) {

	for(int j=0;j<num_list;j++)
	{
		if(strcmp(relay_list[j]->name,name))
			return relay_list[j];
	}
	return NULL;
}

BooleanCalculator::~BooleanCalculator() {

}



BooleanCalculator* BooleanCalculator::Parse(char* expression, int start, int end, Relay** relay_list, int num_list) {
	start=ParseTool::EatWhite(expression,start,end);
	end=ParseTool::EatWhiteBack(expression,end,start);
	int subend;
	BooleanCalculator* term1=NULL;
	BooleanCalculator* term2=NULL;

	int i;
	for(i=start;i<end;)
	{
		switch(expression[i])
		{
		case '&':
			if(term1==NULL)	return NULL;
			term2=BooleanCalculator::Parse(expression,i+1,end, relay_list, num_list);
			return new AndOperator(term1, term2);
			break;
		case '|':
			if(term1==NULL)	return NULL;
			term2=BooleanCalculator::Parse(expression,i+1,end, relay_list, num_list);
			return new OrOperator(term1, term2);
			break;
		case '(':
			subend=ParseTool::EatParenthesis(expression,i,end);
			term1=BooleanCalculator::Parse(expression,i+1,subend, relay_list, num_list);
			i=subend;
			break;
		case '!':
			subend=ParseTool::FindDelimiter(expression, ParseTool::OperationDelimiter, i+1, end);
			term1=BooleanCalculator::Parse(expression,i+1,subend, relay_list, num_list);
			term1=new NotOperator(term1);
			i=subend;
			break;
		default:
			if((expression[i]>='a'&& expression[i]<='z')||(expression[i]>='A'&& expression[i]<='Z'))
			{
				subend=ParseTool::FindDelimiter(expression, ParseTool::OperationDelimiter, i+1, end);
				char name[NAME_SIZE];
				ParseTool::Substring(name,expression, i,subend);

				term1=new RelayOperator(BooleanCalculator::FindRelay(name, relay_list, num_list));
				i=subend;
			}
			else return NULL;
			break;
		}

	}
	return term1;


}


AndOperator::AndOperator(BooleanCalculator* p1, BooleanCalculator* p2) {
	this->param1=p1;
	this->param2=p2;
}

AndOperator::~AndOperator() {
	if(this->param1!=NULL) delete this->param1;
	if(this->param2!=NULL) delete this->param2;
}

bool AndOperator::Calculate() {
	bool a,b;
	a=this->param1->Calculate();
	b=this->param2->Calculate();
	return a&&b;
}

OrOperator::OrOperator(BooleanCalculator* p1, BooleanCalculator* p2) {
	this->param1=p1;
	this->param2=p2;
}

OrOperator::~OrOperator() {
	if(this->param1!=NULL) delete this->param1;
	if(this->param2!=NULL) delete this->param2;
}

bool OrOperator::Calculate() {
	bool a,b;
	a=this->param1->Calculate();
	b=this->param2->Calculate();
	return a||b;
}

NotOperator::NotOperator(BooleanCalculator* p1) {
	this->param1=p1;
}

NotOperator::~NotOperator() {
	if(this->param1!=NULL) delete this->param1;
}

bool NotOperator::Calculate() {
	return !this->param1->Calculate();
}

RelayOperator::RelayOperator(Relay* r) {
	this->relay=r;
}

RelayOperator::~RelayOperator() {
	this->relay=NULL;
}

bool RelayOperator::Calculate() {
	return this->relay->status;
}



} /* namespace PLCLib */
